import numpy as np, scipy.special as sp, copy, re,math
import sys
from model import *

class Run:

    def __init__(self):
        self.model = Model()
        self.model.name = "Run"
        self.model.subscriptions = ["MoveFast"]
        self.model.topNode = "runtop"
        self.model.independent = True

        act1 = Actor()
        act1.name = "dummy1"

        # self.model.subjects.append(act1)

        tnode = Node()
        tnode.getID()
        tnode.name = "runtop"
        tnode.subjects = [act1]
        tnode.objects = []
        tnode.evvecs = []
        tnode.bound = False
        pnode = copy.deepcopy(tnode)
        self.model.topNode = pnode.name
        self.model.nodes.append(pnode)

        tnode.name = "subRun"
        tnode.getID()
        tnode.subjects = [act1]
        tnode.objects = []
        tnode.parents = [pnode]
        tnode.reqActs = dict()
        tnode.reqActs[act1.name] = 1
        tnode.atEnd = True
        tnode.bound = False

        tev = TrackSegment()
        tev.actor = act1
        tev.segtype = Evidence.MOVE_FAST
        tnode.evvecs = [copy.deepcopy(tev)]

        """This function corresponds to the distribution of a runner's speed conditioned on absence of a chase (i.e. default running speed)"""
        def moveNull1(evvecs):
            """runner's location vector"""
            t = evvecs[0]
            locs = t.locations
            dt = float(len(locs))
            speed = t.calcSpeed()
            weight = Run.speedDensityNull(speed)
            return weight

        """each node has a likelihood function which calculates the joint conditional likelihood for all of the evidence it's predicting (this likelihood unique to a node's subject, object, indirect object, and time bindings)"""
        def moveJoint1(evvecs):
            t = evvecs[0]
            """location vector for runner is only item in evvec"""
            locs = t.locations
            dt = float(len(locs))
            speed = t.calcSpeed()
            tweight = Run.speedDensityRun(speed)
            """a single person's run likelihood is only based on his movement speed"""
            fweight = moveNull1(evvecs)
            return tweight,fweight
        tnode.lfunction = moveJoint1
        self.model.nodes.append(copy.deepcopy(tnode))


    """these functions just delegate calls to the chase class's internal model
    this should probably be refactored at some point"""
    def genXML(self):
        return self.model.genXML()

    def printXML(self,outf = None):
        return self.model.printXML(outf)

    def addEv(self,ev):
        #print "adding evidence"
        self.model.addEv(ev)

    def evalEv(self):
        self.model.evaluate_evidence()

    """the methods below call the PDF functions defined in models.py but use parameters which are specific to the chase model"""

    @staticmethod
    def compoundTimeDensity(timediff,arrived = False):
        if arrived:
            return timeDensity(timediff)
        return waitDensity(timediff)

    @staticmethod
    def waitDensity(timediff):
        if timediff < 0:
            return float("-inf")
        tweight = Dists.Surv.gamma(timediff,1.5,1./2.)
        return tweight
    
    @staticmethod
    #def timeDensity(timediff,totlength):
    def timeDensity(timediff):
        if timediff < 0:
            """gamma dist isn't defined for negative values, and this chase model expects the chaser to appear after the chasee"""
            return float("-inf")
        tweight = Dists.PDFs.gamma(timediff,3.75,1.5)
        """estimate time between 1st and 2nd person drawn from gamma with alpha = 3.75, beta = 1.5"""
        return tweight

    @staticmethod
    def speedDensityRun(speed):
        """avg running speed ~14 mph when chased"""
        weight = Dists.PDFs.gamma(speed,14.,1./.45)
        return weight

    @staticmethod
    def sqSpeedDensity(speed):
        weight = Dists.PDFs.egamma(speed,14.,1./.45)
        return weight*weight

    @staticmethod
    def speedDensityNull(speed):
        """avg running speed ~9.4 mph"""
        weight = Dists.PDFs.gamma(speed,6.,1/.7)
        return weight

    
if __name__ == "__main__":
    tRun = Run()

    """read in an old track and generate MovingFast segments from it (both actors use the same location vector but with different times"""
    tfile = open("tfile.txt","r")
    lines = tfile.readlines()
    vals = [[i,[float(x) for x in re.split("\s+",y)[:-1]]] for i,y in enumerate(lines)]
    vals = [x for x in vals if x[1][3] > .5]
    vals = [[x[0],[x[1][0],x[1][2]]] for x in vals]
    vals = vals[107:]
    t1 = vals
    for i in range(len(vals)-1):
        l1 = vals[i][1]
        l2 = vals[i+1][1]
        dx = l2[0]-l1[0]
    t2 = []
    for val in vals:
        tval = copy.deepcopy(val)
        tval[0] = tval[0]+180
        t2.append(tval)

    """create actor and evidence objects associated with the tracks we've built"""
    act1 = Actor()
    act1.name = "person1"
    act1.bound = True
    act1.atype = Actor.PERSON
    act1.track = t1

    ev1 = TrackSegment()
    ev1.actor = act1
    ev1.starttime = t1[0][0]
    ev1.endtime = t1[-1][0]
    ev1.locations = [x[1] for x in t1]
    ev1.segtype = Evidence.MOVE_FAST
    
    act2 = Actor()
    act2.name = "person2"
    act2.bound = True
    act2.atype = Actor.PERSON
    act2.track = t2

    ev2 = TrackSegment()
    ev2.actor = act2
    ev2.starttime = t2[0][0]
    ev2.endtime = t2[-1][0]
    ev2.locations = [x[1] for x in t2]
    ev2.segtype = Evidence.MOVE_FAST

    """instantiate null actor for time evidence"""
    act3 = Actor(True)

    ev3 = Time()
    ev3.actor = act3
    ev3.endtime = ev1.starttime + 150
    #print "start time: "+str(ev3.starttime)+"\n"
    ev3.segtype = Evidence.WAKE

    """pass the evidence we've created into our chase model and calculate the conditional likelihood of the evidence we've passed it for each binding it generates"""
    tRun.addEv(ev1)
    # tRun.evalEv()
    # print "hypotheses after adding evidence 1:\n"
    # tRun.printXML()
    tRun.addEv(ev3)
    tRun.evalEv()
    # print "hypotheses after adding evidence 3:\n"
    # tRun.printXML()
    # tRun.addEv(ev2)
    # tRun.evalEv()
    # print "hypotheses after adding evidence 2:\n"
    # print "likelihoods: ["+",".join([str((np.e**x.likelihood) if (not math.isnan(x.likelihood)) else x.likelihood) for x in tRun.model.hypotheses])+"]"
    tRun.model.printXML(outf = "run",mfiles = True)
    tRun.model.printXML(outf = "run-full.xml")
    # for hyp in testchase.model.hypotheses:
    #     testchase.model.printHypXML(hyp)
    #     print "Querying time with bindings"
    #     print hyp.queryTime("lagtime")
    #     print "Querying time with current time of 500"
    #     print hyp.queryTime("lagtime",500)
    #     print "\n\n"
